<?php
/**
 * Pipahr
 *
 * @author Randy Zhao
 * @copyright 2014 pipahr.com
 */

JTable::addIncludePath(JPATH_ADMINISTRATOR.'/components/com_puser/tables');
JTable::addIncludePath(JPATH_ADMINISTRATOR.'/components/com_jobs/tables');

/**
 * Registration controller class for Users.
 */
class PAccountModelAccount extends JModelLegacy
{
   /**
    * Check User Authorization
    * @param  string $token Authorization From $_POST
    * @param  string $username username From $_POST
    * @return boolean
    */
   public function checkAccessToken($token=null, $username=null) {
      if (empty($token) || empty($username))
         return false;

      $db = PFactory::getDbo();
      $query = "SELECT `username`, `id`, `lastvisitDate`, `password`
               FROM `#__users` WHERE block=0 AND username =".$db->quote($username);
      $db->setQuery($query);
      $result = $db->loadObject();

      if (empty($result))
         return false;

      $parts   = explode(':', $result->password);
      $salt = empty($parts[1]) ? "" : $parts[1];
      $gen_token = shortHash($result->username.$salt.$result->lastvisitDate, 20);
      if ($gen_token == trim($token)) {
         $query = "SELECT time FROM #__users_mobile_token WHERE token = ".$db->quote($gen_token);
         $db->setQuery($query);
         $time = $db->loadResult();

         $lifetime = OC_Config::getValue('mobiletokenlifttime', 0);
         // Token expired or does not exist
         if ( (time()-intval($time)) > $lifetime )
            return false;

         return true;
      }

      return false;
   }

   /**
    * Jobseeker login
    * @return boolean
    */
   public function login() {
      $username = JRequest::getString("username", "");
      $password = JRequest::getString("password", "") ? JRequest::getString("password", "") : ( isset($_SERVER['HTTP_AUTHORIZATION']) ? $_SERVER['HTTP_AUTHORIZATION'] : "" );

      $app = PFactory::getApplication();

      /* perform form login directly; the remember login is controlled by handleRequest */
      $this->directLogin($username, $password);

      if(!OC_User::isLoggedIn()) {
         $this->setErrorCode(20005);
         return false;
      }

      $user = PFactory::getUser();
      // user chould be not valid as if the logged user is jobseeker
      if(!$user->get("guest")) {
         JobHelper::setLastLogonDate($user);
         // Event Driven Cache/Object Caching - clear any cache related to affected tables
         CacheHelper::triggerRemove($user->id, array('#__comprofiler'));
      }

      return true;
   }

   public function directLogin($username, $password) {
      if ( empty($username) || empty($password) ) {
         return false;
      }

      $post = JRequest::get("post");
      OC_App::loadApps();

      // Setup extra user backends
      OC_User::setupBackends();

      if (OC_User::login($username, $password)) {
         // setting up the time zone
         if (isset($post['timezone-offset'])) {
            $_SESSION['timezone'] = $post['timezone-offset'];
         }

         if (!empty($post["remember_login"])) {
            if (defined("DEBUG") && DEBUG) {
               OC_Log::write('core', 'Setting remember login to cookie', OC_Log::DEBUG);
            }

            // Create the encryption key, apply extra hardening using the user agent string.
            $privateKey = PApplication::getHash(@$_SERVER['HTTP_USER_AGENT']);

            $key = new JCryptKey('simple', $privateKey, $privateKey);
            $crypt = new JCrypt(new JCryptCipherSimple, $key);
            $credentials = array('username'=>$email, 'password'=>$password);
            $rcookie = $crypt->encrypt(serialize($credentials));
            $lifetime = time() + 365 * 24 * 60 * 60;

            // Use domain and path set in config for cookie if it exists.
            $cookie_domain = PFactory::getConfig()->get('cookie_domain', '');
            $cookie_path = PFactory::getConfig()->get('cookie_path', '/');
            setcookie(PApplication::getHash('PLOGIN_REMEMBER'), $rcookie, $lifetime, $cookie_path, $cookie_domain);
         }
         return true;
      }
      return false;
   }

   /**
    * Check Login
    * @param  string $username     username in jos_users
    * @param  string $access_token access token from mobile client
    * @return boolean
    *
    * Check User Login Status. If not, try login with access token
    */
   public function checkLogin($username=null, $access_token=null) {
      if (OC_User::isLoggedIn()) {
         $this->updateAccessTokenTime($access_token);
         return true;
      }

      if (empty($username) || empty($access_token))
         return false;

      // Try using access_token to login
      if (!$this->checkAccessToken($access_token, $username))
         return false;

      // Do login, we will check with access_token instead of password (won't update lastvisitDate, means access_token is still valid)
      if (!$this->login())
         return false;

      if (!OC_User::isLoggedIn())
         return false;

      // All good, update access_token time
      $this->updateAccessTokenTime($access_token);

      return true;
   }

   /**
    * Set Access Token After Login
    * @param string $client_id client uuid
    * @param int $uid userid
    * @param string $username user email
    *
    * @return Access Token OR False
    */
   public function setAccessToken($client_id=null, $uid=0, $username=null) {
      if (empty($uid) || empty($username))
         return false;

      $db = PFactory::getDbo();
      // Genarate Token
      $query = "SELECT username,lastvisitDate,password FROM #__users WHERE id = ".intval($uid);
      $db->setQuery($query);
      $result = $db->loadObject();
      if (empty($result))
         return false;

      $parts   = explode(':', $result->password);
      $salt = empty($parts[1]) ? "" : $parts[1];
      $new_token = shortHash($result->username.$salt.$result->lastvisitDate, 20);

      // Adjust frequence to check database
      $config = PFactory::getConfig();
      $handler = $config->get('session_handler', null);
      $freq = 2;
      if($handler != 'database')
         $freq = 60;

      // Remove expired sessions from the database.
      $time = time();
      $lifetime = intval(OC_Config::getValue('mobiletokenlifttime', 0));
      if ($time % $freq == 0) {
         // The modulus introduces a little entropy, making the flushing less accurate
         // but fires the query less than half the time.
         $query = "DELETE FROM #__users_mobile_token WHERE time < ".intval($time - $lifetime);
         $db->setQuery($query);
         $db->execute();
      }

      // Save new token to db
      $query = "INSERT INTO #__users_mobile_token SET token = ".$db->quote($new_token).", client_id = ".$db->quote($client_id).", time = ".time().", uid = ".intval($uid).", username = ".$db->quote($username)." ON DUPLICATE KEY UPDATE token=values(token),client_id=values(client_id),time=values(time)";
      $db->setQuery($query);

      $lifetime = OC_Config::getValue('mobiletokenlifttime', 0);
      return $db->execute() ? array("access_token"=>$new_token,"expires_in"=>$lifetime) : false;
   }

   /**
    * Function getJobseekerInfo
    * @param  string $userid  Jobseeker id
    * @return array           Jobseeker info array
    */
   public function getJobseekerInfo($userid) {
      if (empty($userid))
         return null;

      $db = PFactory::getDbo();
      $query = "SELECT u.id, u.name, u.email, m.mobile AS phone, c.cb_lastlogondate AS lastest_login,
         IF(j.sex IS NULL,jj.sex,j.sex) AS sex,IF(j.dateofbirth IS NULL,jj.dateofbirth,j.dateofbirth) AS dateofbirth,IF(j.province IS NULL,jj.province,j.province) AS province,IF(j.id_province IS NULL,jj.id_province,j.id_province) AS id_province,IF(j.city IS NULL,jj.city,j.city) AS city,IF(j.id_city IS NULL,jj.id_city,j.id_city) AS id_city,
         (SELECT COUNT(*) FROM #__persontest_result WHERE user_id=u.id) AS completed_person_test
         FROM #__users AS u
         LEFT JOIN #__users_mobile AS m ON m.userid=u.id AND m.primary=1
         LEFT JOIN #__comprofiler AS c ON c.user_id=u.id
         LEFT JOIN *PREFIX*hr_jobseeker AS j ON j.email=u.email
         LEFT JOIN *PREFIX*hr_jobseeker AS jj ON jj.phone=m.mobile
         WHERE u.id=".intval($userid)." GROUP BY u.id";

      $db->setQuery(PUtil::replaceOCPrefix($query));
      $result = $db->loadAssoc();

      return !empty($result) ? $result : null;
   }

   /**
    * Update access token time.
    * @param  string $access_token Access token need to be updated
    * @return boolean
    */
   public function updateAccessTokenTime($access_token) {
      if (empty($access_token))
         return false;

      $db = PFactory::getDbo();
      $query = "UPDATE #__users_mobile_token SET time = ".time()." WHERE token = ".$db->quote($access_token);
      $db->setQuery($query);

      return $db->execute();
   }

   /**
    * Add new mobile for this user
    * @param int    $uid    user id
    * @param string $mobile new mobile number
    */
   public function addNewMobile($uid, $mobile, $primary=false) {
      if (empty($uid) || empty($mobile)) {
         return false;
      }

      $db = PFactory::getDbo();
      if ($primary) {
         $query = "INSERT INTO #__users_mobile SET userid = ".intval($uid).", mobile = ".$db->quote($mobile).", `primary`=1 ON DUPLICATE KEY UPDATE userid=values(userid),mobile=values(mobile),`primary`=values(`primary`)";
      } else {
         $query = "INSERT INTO #__users_mobile SET userid = ".intval($uid).", mobile = ".$db->quote($mobile)." ON DUPLICATE KEY UPDATE userid=values(userid),mobile=values(mobile)";
      }
      $db->setQuery($query);
      return $db->execute();
   }

   public function updateUserEmail($user, $email) {
      if (empty($user) || empty($email) || isFakeEmail($email))
         return false;

      $db = PFactory::getDbo();
      $query = "UPDATE #__users SET username = ".$db->quote($email).", email = ".$db->quote($email)." WHERE id = ".intval($user->id);
      $db->setQuery($query);
      if ($db->execute()) {
         // Change user session
         $app = PFactory::getApplication();
         $user->set('username', $email);
         $user->set('email', $email);
         $app->setUserSession($user);
         return true;
      }
      return false;
   }

   public function postFeedback() {
      $user = PFactory::getUser();
      $type = JRequest::getString("type","feedback");

      if ($type != "crash" && empty($user)) {
         $this->setErrorCode(20002);
         $this->setError('获取用户基本信息失败');
         return false;
      }

      $feedback_text = JRequest::getString('feedback','');
      if (empty($feedback_text)) {
         $this->setErrorCode(20013);
         $this->setError('请认真填写反馈');
         return false;
      }

      $userid = !empty($user->id) ? $user->id : 0;
      $username = !empty($user->username) ? $user->username : "";
      $client_id = JRequest::getString('uuid','');
      $app_version = JRequest::getString('versionCode','');
      $model = trim(JRequest::getString('manufacturer','')." ".JRequest::getString('model',''));
      $resolution = JRequest::getString('screenHeight','')."x".JRequest::getString('screenWidth','');
      $os_version = JRequest::getString('osVersion','');
      $sdk_version = JRequest::getString('sdkVersion','');

      $db = PFactory::getDbo();
      $query = "INSERT INTO jos_users_mobile_feedback SET type = ".$db->quote($type).", userid = ".intval($userid).", username = ".$db->quote($username).", feedback_text = ".$db->quote($feedback_text).", time = ".time().", client_id = ".$db->quote($client_id).", app_version = ".$db->quote($app_version).", model = ".$db->quote($model).", resolution = ".$db->quote($resolution).", os_version = ".$db->quote($os_version).", sdk_version = ".$db->quote($sdk_version);
      $db->setQuery($query);
      if (!$db->execute()) {
         $this->setErrorCode(20014);
         $this->setError('反馈失败, 请重试');
         return false;
      }
      return true;
   }

}
